{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "## 脚本、模块、包、库\n",
    "python 中自带了很多标准，我们很多程序其实是利用标准库来完成。要理解库的概念，首先要了解脚本、模块、包的相关知识。\n",
    "通常我们写的能在命令行运行的python程序，称之为脚本。\n",
    "任何一个.py文件都可以是一个模块\n",
    "包是模块的集合\n",
    "库是包和模块的集合，规模更大，一般我们用系统库就够了。python还提供了大量的第三方库。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "15.811388300841896\n",
      "15.811388300841896\n",
      "15.811388300841896\n"
     ]
    }
   ],
   "source": [
    "# 标准库的导入\n",
    "import math\n",
    "print(math.sqrt(250))\n",
    "from math import sqrt\n",
    "print(sqrt(250))\n",
    "from math import sqrt as kf\n",
    "print(kf(250))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "#我把上次课的例子，做成health.py文件，放当前目录下面\n",
    "#如何运行\n",
    "import health\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(学号:11111111，姓名:haha，健康码:红码,班级:111,学院:rrrr,原因:在国外)\n",
      "[(学号:11111111，姓名:甲，健康码:红马,班级:光伏1902\n",
      "\n",
      ",学院:电子信息学院,原因:湖北旅居史), (学号:11111112，姓名:乙，健康码:皇马,班级:海军通信1803,学院:士官学院,原因:湖北旅居史), (学号:11111113，姓名:丙，健康码:绿马,班级:光伏1902,学院:电子信息学院,原因:湖北旅居史), (学号:11111114，姓名:丁，健康码:红马,班级:应用电子1801,学院:电子信息学院,原因:湖北旅居史), (学号:11111115，姓名:戊，健康码:皇马,班级:韩语1801,学院:电子信息学院,原因:湖北旅居史), (学号:11111116，姓名:己，健康码:绿马,班级:动画1701,学院:数码艺术学院,原因:湖北旅居史), (学号:11111117，姓名:庚，健康码:红马,班级:应用电子1801,学院:电子信息学院,原因:湖北旅居史), (学号:11111118，姓名:辛，健康码:皇马,班级:数媒技术1701,学院:数码艺术学院,原因:湖北旅居史), (学号:11111119，姓名:壬，健康码:绿马,班级:电气1701,学院:电子信息学院,原因:湖北旅居史), (学号:11111120，姓名:癸，健康码:红马,班级:计算机网络1701,学院:网络与通信学院,原因:湖北旅居史), (学号:11111121，姓名:甲，健康码:皇马,班级:电子信息1702,学院:电子信息学院,原因:湖北旅居史), (学号:11111122，姓名:乙，健康码:绿马,班级:光伏1901,学院:电子信息学院,原因:湖北旅居史), (学号:11111123，姓名:丙，健康码:红马,班级:韩语1801,学院:电子信息学院,原因:湖北旅居史), (学号:11111124，姓名:丁，健康码:皇马,班级:虚拟技术1901,学院:数码艺术学院,原因:湖北旅居史), (学号:11111125，姓名:戊，健康码:绿马,班级:电子商务1901,学院:数字商务学院,原因:湖北旅居史), (学号:11111126，姓名:己，健康码:红马,班级:电气1702,学院:电子信息学院,原因:湖北旅居史), (学号:11111127，姓名:庚，健康码:皇马,班级:视传1701,学院:数码艺术学院,原因:湖北旅居史), (学号:11111128，姓名:辛，健康码:绿马,班级:软件1903,学院:人工智能学院,原因:湖北旅居史), (学号:11111129，姓名:壬，健康码:红马,班级:机电1804,学院:智能制造学院,原因:湖北旅居史), (学号:11111130，姓名:癸，健康码:皇马,班级:应用电子1901,学院:电子信息学院,原因:湖北旅居史), (学号:11111131，姓名:甲，健康码:绿马,班级:电子质检1903,学院:电子信息学院,原因:湖北旅居史), (学号:11111132，姓名:乙，健康码:红马,班级:电子质检1902,学院:电子信息学院,原因:湖北旅居史), (学号:11111133，姓名:丙，健康码:皇马,班级:电气1701,学院:电子信息学院,原因:湖北旅居史), (学号:11111134，姓名:丁，健康码:绿马,班级:物联网1804,学院:网络与通信学院,原因:湖北旅居史), (学号:11111135，姓名:戊，健康码:红马,班级:数媒技术1701,学院:数码艺术学院,原因:湖北旅居史), (学号:11111136，姓名:己，健康码:皇马,班级:机电1902,学院:智能制造学院,原因:湖北旅居史), (学号:11111137，姓名:庚，健康码:绿马,班级:软件1705,学院:人工智能学院,原因:湖北旅居史), (学号:11111138，姓名:辛，健康码:红马,班级:模具1801,学院:智能制造学院,原因:湖北旅居史), (学号:11111139，姓名:壬，健康码:皇马,班级:物联网1702,学院:网络与通信学院,原因:湖北旅居史), (学号:11111140，姓名:癸，健康码:绿马,班级:移动应用1903,学院:人工智能学院,原因:湖北旅居史), (学号:11111141，姓名:甲，健康码:红马,班级:电子商务1901,学院:数字商务学院,原因:湖北旅居史), (学号:11111142，姓名:乙，健康码:皇马,班级:动画1803,学院:数码艺术学院,原因:湖北旅居史), (学号:11111143，姓名:丙，健康码:绿马,班级:环境1802,学院:电子信息学院,原因:湖北旅居史), (学号:11111144，姓名:丁，健康码:红马,班级:火箭计网1901,学院:士官学院,原因:湖北旅居史), (学号:11111145，姓名:戊，健康码:皇马,班级:数媒技术1902,学院:数码艺术学院,原因:湖北旅居史), (学号:11111146，姓名:己，健康码:绿马,班级:数控1702,学院:智能制造学院,原因:湖北旅居史), (学号:11111111，姓名:甲，健康码:红马,班级:光伏1902\n",
      "\n",
      ",学院:电子信息学院,原因:境外旅居史)]\n"
     ]
    }
   ],
   "source": [
    "#我们上次课定义的类文件可以作为模块被引用\n",
    "#从文件导入 \n",
    "from health import test\n",
    "test()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(学号:11111111，姓名:haha，健康码:红码,班级:111,学院:rrrr,原因:在国外)\n",
      "[(学号:11111111，姓名:甲，健康码:红马,班级:光伏1902\n",
      "\n",
      ",学院:电子信息学院,原因:湖北旅居史), (学号:11111112，姓名:乙，健康码:皇马,班级:海军通信1803,学院:士官学院,原因:湖北旅居史), (学号:11111113，姓名:丙，健康码:绿马,班级:光伏1902,学院:电子信息学院,原因:湖北旅居史), (学号:11111114，姓名:丁，健康码:红马,班级:应用电子1801,学院:电子信息学院,原因:湖北旅居史), (学号:11111115，姓名:戊，健康码:皇马,班级:韩语1801,学院:电子信息学院,原因:湖北旅居史), (学号:11111116，姓名:己，健康码:绿马,班级:动画1701,学院:数码艺术学院,原因:湖北旅居史), (学号:11111117，姓名:庚，健康码:红马,班级:应用电子1801,学院:电子信息学院,原因:湖北旅居史), (学号:11111118，姓名:辛，健康码:皇马,班级:数媒技术1701,学院:数码艺术学院,原因:湖北旅居史), (学号:11111119，姓名:壬，健康码:绿马,班级:电气1701,学院:电子信息学院,原因:湖北旅居史), (学号:11111120，姓名:癸，健康码:红马,班级:计算机网络1701,学院:网络与通信学院,原因:湖北旅居史), (学号:11111121，姓名:甲，健康码:皇马,班级:电子信息1702,学院:电子信息学院,原因:湖北旅居史), (学号:11111122，姓名:乙，健康码:绿马,班级:光伏1901,学院:电子信息学院,原因:湖北旅居史), (学号:11111123，姓名:丙，健康码:红马,班级:韩语1801,学院:电子信息学院,原因:湖北旅居史), (学号:11111124，姓名:丁，健康码:皇马,班级:虚拟技术1901,学院:数码艺术学院,原因:湖北旅居史), (学号:11111125，姓名:戊，健康码:绿马,班级:电子商务1901,学院:数字商务学院,原因:湖北旅居史), (学号:11111126，姓名:己，健康码:红马,班级:电气1702,学院:电子信息学院,原因:湖北旅居史), (学号:11111127，姓名:庚，健康码:皇马,班级:视传1701,学院:数码艺术学院,原因:湖北旅居史), (学号:11111128，姓名:辛，健康码:绿马,班级:软件1903,学院:人工智能学院,原因:湖北旅居史), (学号:11111129，姓名:壬，健康码:红马,班级:机电1804,学院:智能制造学院,原因:湖北旅居史), (学号:11111130，姓名:癸，健康码:皇马,班级:应用电子1901,学院:电子信息学院,原因:湖北旅居史), (学号:11111131，姓名:甲，健康码:绿马,班级:电子质检1903,学院:电子信息学院,原因:湖北旅居史), (学号:11111132，姓名:乙，健康码:红马,班级:电子质检1902,学院:电子信息学院,原因:湖北旅居史), (学号:11111133，姓名:丙，健康码:皇马,班级:电气1701,学院:电子信息学院,原因:湖北旅居史), (学号:11111134，姓名:丁，健康码:绿马,班级:物联网1804,学院:网络与通信学院,原因:湖北旅居史), (学号:11111135，姓名:戊，健康码:红马,班级:数媒技术1701,学院:数码艺术学院,原因:湖北旅居史), (学号:11111136，姓名:己，健康码:皇马,班级:机电1902,学院:智能制造学院,原因:湖北旅居史), (学号:11111137，姓名:庚，健康码:绿马,班级:软件1705,学院:人工智能学院,原因:湖北旅居史), (学号:11111138，姓名:辛，健康码:红马,班级:模具1801,学院:智能制造学院,原因:湖北旅居史), (学号:11111139，姓名:壬，健康码:皇马,班级:物联网1702,学院:网络与通信学院,原因:湖北旅居史), (学号:11111140，姓名:癸，健康码:绿马,班级:移动应用1903,学院:人工智能学院,原因:湖北旅居史), (学号:11111141，姓名:甲，健康码:红马,班级:电子商务1901,学院:数字商务学院,原因:湖北旅居史), (学号:11111142，姓名:乙，健康码:皇马,班级:动画1803,学院:数码艺术学院,原因:湖北旅居史), (学号:11111143，姓名:丙，健康码:绿马,班级:环境1802,学院:电子信息学院,原因:湖北旅居史), (学号:11111144，姓名:丁，健康码:红马,班级:火箭计网1901,学院:士官学院,原因:湖北旅居史), (学号:11111145，姓名:戊，健康码:皇马,班级:数媒技术1902,学院:数码艺术学院,原因:湖北旅居史), (学号:11111146，姓名:己，健康码:绿马,班级:数控1702,学院:智能制造学院,原因:湖北旅居史), (学号:11111111，姓名:甲，健康码:红马,班级:光伏1902\n",
      "\n",
      ",学院:电子信息学院,原因:境外旅居史)]\n"
     ]
    }
   ],
   "source": [
    "#随之文件越来越多，可以把这些文件制作成包\n",
    "#包本质上是个文件夹，里面有个__init__.py文件，用于和普通文件夹进行区别\n",
    "#我们把health.py 和 excel.xlsx放到文件夹phealth中，并在phealth中添加__init__.py文件，什么内容也不写\n",
    "#让引用包，并运行里面的程序\n",
    "#注意：自己包如果让其它python程序访问，可以放在当前目录，也可放在PYTHONPATH指定目录中。\n",
    "#python搜索包的顺序是，首先是不是内置包，如果是则访问内置包\n",
    "#如果不是则先找当前目录，然后是PYTHONPATH指定目录,然后是系统安装目录，\n",
    "#实在找不到，就抛出ImportError错误\n",
    "from phealth.health import test\n",
    "#from phealth.health.test #当所有层次都是包的时候，这种写法才有用\n",
    "test()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "5.0\n",
      "Point(x=3, y=4)\n",
      "(5, 8)\n"
     ]
    }
   ],
   "source": [
    "#在CPython里面有很多pyc文件，这个是编译后的模块，可以提高加载速度\n",
    "#下面我们来学习python中内置库的使用\n",
    "#collections.namedtuple 命名元组\n",
    "import math\n",
    "import collections\n",
    "Point = collections.namedtuple('Point',['x','y'])\n",
    "#很容易创建一个新的类型，代码可读性比普通元组强,一看就知道这是Point类型\n",
    "#代码的最高境界，不是注释多，是自解释\n",
    "p = Point(3,y=4)\n",
    "p2 = (5,8)\n",
    "print(math.sqrt(p.x*p.x+p.y*p.y))\n",
    "#输出可读性也很强\n",
    "print(p)\n",
    "print(p2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'20020178': [15, 20], '170430301': [25, 15, 20]}\n",
      "defaultdict(<class 'list'>, {'20020178': [15, 20], '170430301': [25, 15, 20]})\n"
     ]
    }
   ],
   "source": [
    "#collections.defaultdict  防止key不存在造成的异常\n",
    "#加入有点餐记录\n",
    "diancan = [('20020178',15),('170430301',25),('20020178',20),('170430301',15),('170430301',20)]\n",
    "#能否变成字典\n",
    "dicdc = {'20020178':[15,20],'170430301':[25,15,20]}\n",
    "#我们可以这么实现\n",
    "dicdc = {}\n",
    "for k,v in diancan:\n",
    "    #防止key不存在造成异常\n",
    "    if k not in dicdc:\n",
    "        dicdc[k]=[]\n",
    "    dicdc[k].append(v)\n",
    "print(dicdc)\n",
    "#也可以这么实现\n",
    "dicdc=collections.defaultdict(lambda:list())\n",
    "#也可以\n",
    "#dicdc=collections.defaultdict(list)\n",
    "#如果默认值0也可以\n",
    "#collections.defaultdict(lambda:0)\n",
    "#collections.defaultdict(int)\n",
    "for k,v in diancan:\n",
    "    dicdc[k].append(v)\n",
    "print(dicdc)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#任务7-1  通过前面所学，实现教师食堂点餐统计，一个月内教师点餐消费记录\n",
    "#请产生每个人的消费记录和总金额"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Counter({'特朗普': 4, '拜登': 4, '彭斯': 4})\n",
      "[('特朗普', 4), ('拜登', 4), ('彭斯', 4)]\n"
     ]
    }
   ],
   "source": [
    "#collections.Counter 集合的计数功能\n",
    "#可以大大简化数据的统计处理，如果自己写循环处理起来很麻烦\n",
    "import collections\n",
    "toupiao = ['特朗普','拜登','彭斯','特朗普','拜登','彭斯','特朗普','拜登','彭斯','特朗普','拜登','彭斯']\n",
    "toupiaojieguo = collections.Counter(toupiao)\n",
    "print(toupiaojieguo)\n",
    "print(list(toupiaojieguo.items()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Counter({'特朗普': 4, '拜登': 4, '彭斯': 4, '任俊新': 1, '任哥': 1, '哈哈': 1})\n",
      "[('特朗普', 4), ('拜登', 4), ('彭斯', 4), ('任俊新', 1), ('任哥', 1), ('哈哈', 1)]\n"
     ]
    }
   ],
   "source": [
    "#还可以增加计数的内容\n",
    "toupiaojieguo += collections.Counter(['任俊新','任哥','哈哈'])\n",
    "print(toupiaojieguo)\n",
    "print(list(toupiaojieguo.items()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[('特朗普', 4), ('拜登', 4), ('彭斯', 4)]\n"
     ]
    }
   ],
   "source": [
    "#可以对投票结果取前几名\n",
    "top3 = toupiaojieguo.most_common(3)\n",
    "print(top3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Counter({'特朗普': 4, '拜登': 4, '彭斯': 4, '任哥': 1, '哈哈': 1})\n"
     ]
    }
   ],
   "source": [
    "#可以减去计数内容\n",
    "toupiaojieguo -= collections.Counter(['任俊新'])\n",
    "print(toupiaojieguo)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 日期和时间\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Python中对日期和时间的处理，主要的内置模块有time和datetime。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### time模块"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "time.struct_time(tm_year=2021, tm_mon=9, tm_mday=18, tm_hour=14, tm_min=50, tm_sec=26, tm_wday=5, tm_yday=261, tm_isdst=0)\n",
      "time.struct_time(tm_year=2021, tm_mon=9, tm_mday=18, tm_hour=6, tm_min=50, tm_sec=26, tm_wday=5, tm_yday=261, tm_isdst=0)\n",
      "time.struct_time(tm_year=1970, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=1, tm_isdst=0)\n",
      "-28800\n",
      "1631947826.5504084\n",
      "1631947826550408500\n",
      "Sat Sep 18 14:50:26 2021\n"
     ]
    }
   ],
   "source": [
    "#time模块\n",
    "import time\n",
    "#查看当前本地时间\n",
    "print(time.localtime())\n",
    "#查看当前格林威治时间,发现小时差了8小时，因为我们所在的时区是UTC+8\n",
    "print(time.gmtime())\n",
    "#查看起始时间,可以发现是从1970年1月1日开始的\n",
    "print(time.gmtime(0))\n",
    "#查看时区,-28800 表示-8*3600秒\n",
    "print(time.timezone)\n",
    "#查看从1970年1月1日到现在多少秒\n",
    "print(time.time())\n",
    "#查看1970年1月1日到现在多少纳秒\n",
    "print(time.time_ns())\n",
    "#查看字符串格式时间\n",
    "print(time.ctime())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "t: 1631947939.6462464\n",
      "t1: 2021年09月18日 14:52:19 t2: 2021年09月18日 06:52:19\n",
      "False\n",
      "t3: time.struct_time(tm_year=2021, tm_mon=9, tm_mday=18, tm_hour=12, tm_min=58, tm_sec=25, tm_wday=5, tm_yday=261, tm_isdst=-1)\n",
      "t3num: 1631941105.0\n",
      "t4: 2021年09月18日 04:58:25\n"
     ]
    }
   ],
   "source": [
    "#时间的格式化\n",
    "import time\n",
    "t = time.time()\n",
    "print(\"t:\",t)   # 得到时间戳\n",
    "t1 = time.localtime(t)\n",
    "t2 = time.gmtime(t)\n",
    "time_format = \"%Y年%m月%d日 %H:%M:%S\"\n",
    "print(\"t1:\",time.strftime(time_format,t1),\"t2:\",time.strftime(time_format,t2))\n",
    "#虽然时间相同，但两个对象并不相等\n",
    "print(t1==t2)\n",
    "\n",
    "st3 = \"2021年09月18日 12:58:25\"\n",
    "#得到的是localtime\n",
    "t3 = time.strptime(st3, time_format)\n",
    "print(\"t3:\",t3)\n",
    "t3num = time.mktime(t3)\n",
    "print(\"t3num:\", t3num)\n",
    "\n",
    "t4 = time.gmtime(t3num)\n",
    "#得到标准时间，发现和t3差了8个小时，验证了strptime得到的是本地时间\n",
    "print(\"t4:\",time.strftime(time_format,t4))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Sat Sep 18 14:51:57 2021\n",
      "Sat Sep 18 13:51:57 2021\n"
     ]
    }
   ],
   "source": [
    "#时间的加减\n",
    "import time\n",
    "t = time.time()\n",
    "print(time.ctime(t))\n",
    "t -= 3600\n",
    "print(time.ctime(t))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### datetime模块\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2021-09-18 16:08:36.739956\n",
      "2021年09月18日 16:08:36\n"
     ]
    }
   ],
   "source": [
    "from datetime import datetime,timezone\n",
    "t = datetime.now()\n",
    "print(t)\n",
    "time_format = \"%Y年%m月%d日 %H:%M:%S\"\n",
    "print(t.strftime(time_format))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 114,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2021-09-04 23:27:29.249163\n",
      "918过去了 32873 天，勿忘历史，落后就要挨打\n",
      "2021-09-18 00:00:00 2021-09-18\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "#时间+-\n",
    "from datetime import datetime, timedelta\n",
    "#往前14天\n",
    "td = timedelta(days = -14)\n",
    "\n",
    "now = datetime.now()\n",
    "print(now + td)\n",
    "\n",
    "t918 = datetime(1931,9,18)  \n",
    "delta = datetime.now()-t918\n",
    "\n",
    "print(\"918过去了\",delta.days,'天，勿忘历史，落后就要挨打')\n",
    "\n",
    "print(datetime(2021,9,18),now.date())\n",
    "\n",
    "print(datetime(2021,9,18)==now.date())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 115,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2021-09-18 00:00:00 2021-09-18 00:00:00+00:00 2021-09-18 08:00:00+08:00\n"
     ]
    }
   ],
   "source": [
    "#时区\n",
    "from datetime import datetime, timezone\n",
    "t = datetime(2021,9,18)\n",
    "utc_t = t.replace(tzinfo=timezone.utc)\n",
    "lt = utc_t.astimezone()\n",
    "print(t,utc_t,lt)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 正则表达式\n",
    "我们在文本处理的时候最高效的莫过于使用正则表达式了。当我们爬取各种信息的时候，如何提取出有用的信息？当我们获取用户输入的时候，如果检测用户输入是否合法？这些都需要正则表达式的支持。python提供了perl风格的正则表达式，功能非常强大，除了可以分析，搜索，验证之外，还可以进行字符串的替换和分割等操作。\n",
    "\n",
    "更详细的教程请参照：https://docs.python.org/zh-cn/3/library/re.html"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(6, 8), match='任哥'>\n",
      "6\n",
      "8\n",
      "<re.Match object; span=(16, 19), match='day'>\n",
      "16\n",
      "19\n",
      "任哥\n",
      "day\n",
      "()\n"
     ]
    }
   ],
   "source": [
    "#re.search 查找字符串\n",
    "#语法: re.search(pattern,string,flags=0)\n",
    "#pattern:正则表达式\n",
    "#string:要匹配的字符串\n",
    "#flags:标志位，控制正则表达式的匹配方式，如区分大小写，多行匹配等\n",
    "#匹配成功会返回一个匹配的对象，否则返回None\n",
    "#可以使用groups()或group(num)来获取匹配的对象\n",
    "#groups()所有匹配对象的元组\n",
    "#group(num=0)获取匹配对象\n",
    "import re\n",
    "m0 = re.search(\"任哥\",\"大家没有见过任哥，其实任哥只是个传说\")\n",
    "m1 = re.search(\"day\",\"good good study day day up\")\n",
    "#输出match结果\n",
    "print(m0)\n",
    "print(m0.start())\n",
    "print(m0.end())\n",
    "print(m1)\n",
    "print(m1.start())\n",
    "print(m1.end())\n",
    "#匹配的对象\n",
    "print(m0.group())\n",
    "print(m1.group())\n",
    "#没有设置组，所以groups没有东西\n",
    "print(m0.groups())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 转义字符\n",
    "对于回车换行等特殊字符的匹配，我们可以使用转义字符来进行匹配\n",
    "常见的转义字符，如表所示。\n",
    "\n",
    "|转义字符|含义|\n",
    "|  ----  |  ----  |\n",
    "|\\\\newline|忽略换行|\n",
    "|\\\\\\\\|反斜杠（\\\\）|\n",
    "|\\\\'|单引号（'）|\n",
    "|\\\\\"|双引号（\"）|\n",
    "|\\\\a|ASCII蜂鸣（BEL）|\n",
    "|\\\\b|ASCII退格（BS）|\n",
    "|\\\\f|ASCII换页（FF）|\n",
    "|\\\\n|ASCII换行（LF）|\n",
    "|\\\\N{name}|给定名称的Unicode字符|\n",
    "|\\\\ooo|给定八进制值的字符|\n",
    "|\\\\r|ASCII回车符（CR）|\n",
    "|\\\\t|ASCII制表符（TAB）|\n",
    "|\\\\uhhhh|给定16位十六进制值的Unicode字符|\n",
    "|\\\\Uhhhhhhhh|给定32位十六进制值的Unicode字符|\n",
    "|\\\\v|ASCII垂直指标（VT）|\n",
    "|\\\\xhh|给定8位十六进制值的Unicode字符|"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(12, 17), match='\\nJust'>\n",
      "12\n",
      "17\n",
      "10\n",
      "<re.Match object; span=(12, 17), match='\\nJust'>\n",
      "12\n",
      "17\n",
      "5b57\n",
      "<re.Match object; span=(11, 17), match='字\\nJust'>\n",
      "11\n",
      "17\n"
     ]
    }
   ],
   "source": [
    "content = \"\"\" 任哥说，学编程就一个字\n",
    "Just Do it!!!!\n",
    "\"\"\"\n",
    "m0 = re.search(\"\\nJust\",content)\n",
    "#输出match结果\n",
    "print(m0)\n",
    "print(m0.start())\n",
    "print(m0.end())\n",
    "#获取\\n的编码\n",
    "print(ord(\"\\n\"))\n",
    "#使用\\xhh来匹配\n",
    "m1 = re.search(\"\\x0aJust\",content)\n",
    "print(m1)\n",
    "print(m1.start())\n",
    "print(m1.end())\n",
    "#获取“字”的编码\n",
    "print(\"{:x}\".format(ord(\"字\")))\n",
    "#使用\\uhhhh和\\ooo匹配（10的8进制是012)\n",
    "m2 = re.search(\"\\u5b57\\012Just\",content)\n",
    "print(m2)\n",
    "print(m2.start())\n",
    "print(m2.end())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 正则表达式匹配模式"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "#正则表达式的模式主要有以下这些种类：\n",
    "#^\t匹配字符串的开头\n",
    "#$\t匹配字符串的末尾。\n",
    "#.\t匹配任意字符，除了换行符，当re.DOTALL标记被指定时，则可以匹配包括换行符的任意字符。\n",
    "#[...]\t用来表示一组字符,单独列出：[amk] 匹配 'a'，'m'或'k'\n",
    "#[^...]\t不在[]中的字符：[^abc] 匹配除了a,b,c之外的字符。\n",
    "#re*\t匹配0个或多个的表达式。\n",
    "#re+\t匹配1个或多个的表达式。\n",
    "#re?\t匹配0个或1个由前面的正则表达式定义的片段，非贪婪方式\n",
    "#re{ n}\t精确匹配 n 个前面表达式。例如， o{2} 不能匹配 \"Bob\" 中的 \"o\"，但是能匹配 \"food\" 中的两个 o。\n",
    "#re{ n,}\t匹配 n 个前面表达式。例如， o{2,} 不能匹配\"Bob\"中的\"o\"，但能匹配 \"foooood\"中的所有 o。\"o{1,}\" 等价于 \"o+\"。\"o{0,}\" 则等价于 \"o*\"。\n",
    "#re{ n, m}\t匹配 n 到 m 次由前面的正则表达式定义的片段，贪婪方式\n",
    "#a| b\t匹配a或b\n",
    "#(re)\t对正则表达式分组并记住匹配的文本\n",
    "#(?imx)\t正则表达式包含三种可选标志：i, m, 或 x 。只影响括号中的区域。\n",
    "#(?-imx)\t正则表达式关闭 i, m, 或 x 可选标志。只影响括号中的区域。\n",
    "#(?: re)\t类似 (...), 但是不表示一个组\n",
    "#(?imx: re)\t在括号中使用i, m, 或 x 可选标志\n",
    "#(?-imx: re)\t在括号中不使用i, m, 或 x 可选标志\n",
    "#(?#...)\t注释.\n",
    "#(?= re)\t前向肯定界定符。如果所含正则表达式，以 ... 表示，在当前位置成功匹配时成功，否则失败。但一旦所含表达式已经尝试，匹配引擎根本没有提高；模式的剩余部分还要尝试界定符的右边。\n",
    "#(?! re)\t前向否定界定符。与肯定界定符相反；当所含表达式不能在字符串当前位置匹配时成功\n",
    "#(?> re)\t匹配的独立模式，省去回溯。\n",
    "#\\w\t匹配字母数字及下划线\n",
    "#\\W\t匹配非字母数字及下划线\n",
    "#\\s\t匹配任意空白字符，等价于 [\\t\\n\\r\\f].\n",
    "#\\S\t匹配任意非空字符\n",
    "#\\d\t匹配任意数字，等价于 [0-9()].\n",
    "#\\D\t匹配任意非数字\n",
    "#\\A\t匹配字符串开始\n",
    "#\\Z\t匹配字符串结束，如果是存在换行，只匹配到换行前的结束字符串。\n",
    "#\\z\t匹配字符串结束\n",
    "#\\G\t匹配最后匹配完成的位置。\n",
    "#\\b\t匹配一个单词边界，也就是指单词和空格间的位置。例如， 'er\\b' 可以匹配\"never\" 中的 'er'，但不能匹配 \"verb\" 中的 'er'。\n",
    "#\\B\t匹配非单词边界。'er\\B' 能匹配 \"verb\" 中的 'er'，但不能匹配 \"never\" 中的 'er'。\n",
    "#\\1...\\9\t匹配第n个分组的内容。\n",
    "#\\10\t匹配第n个分组的内容，如果它经匹配。否则指的是八进制字符码的表达式。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(1, 3), match='哈哈'>\n",
      "<re.Match object; span=(0, 2), match='哈哈'>\n",
      "None\n",
      "<re.Match object; span=(0, 2), match='哈哈'>\n",
      "None\n",
      "<re.Match object; span=(0, 2), match='哈哈'>\n",
      "None\n"
     ]
    }
   ],
   "source": [
    "#从开头开始匹配，相当于match\n",
    "m0 = re.search('哈哈','我哈哈哈哈哈哈')\n",
    "print(m0)\n",
    "m1 = re.search('^哈哈','哈哈哈哈哈哈')\n",
    "print(m1)\n",
    "m2 = re.search('^哈哈','我哈哈哈哈哈')\n",
    "print(m2)\n",
    "m3 = re.match('哈哈','哈哈哈哈哈哈')\n",
    "print(m3)\n",
    "m4 = re.match('哈哈','我哈哈哈哈哈哈')\n",
    "print(m4)\n",
    "#开头结尾全匹配,这就相当于match了\n",
    "m0 = re.match('^哈哈$','哈哈')\n",
    "print(m0)\n",
    "m1 = re.match('^哈哈$','哈哈哈哈')\n",
    "print(m1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(0, 1), match='哈'>\n",
      "<re.Match object; span=(0, 3), match='哈哈哈'>\n",
      "<re.Match object; span=(0, 3), match='哈哈哈'>\n"
     ]
    }
   ],
   "source": [
    "#. *的用法\n",
    "#一个字符\n",
    "m0 = re.search('.','哈哈哈哈')\n",
    "print(m0)\n",
    "#多个字符\n",
    "m1 = re.search('.*','哈哈哈')\n",
    "print(m1)\n",
    "#带换行,默认是除了换行\n",
    "mline = \"\"\"哈哈哈\n",
    "哈哈\"\"\"\n",
    "m2 = re.search('.*',mline)\n",
    "print(m2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(1, 3), match='ou'>\n",
      "<re.Match object; span=(1, 4), match='ou '>\n",
      "<re.Match object; span=(8, 10), match='ou'>\n",
      "<re.Match object; span=(8, 11), match='our'>\n",
      "None\n"
     ]
    }
   ],
   "source": [
    "#位置匹配 ^, $, \\b, \\B, \\<, \\>, \\A, \\Z\n",
    "# ^匹配一行的开始 $匹配一行的结束\n",
    "#\\b匹配\\w和\\W之间的空字符串,还匹配\\w和整个字符串的开头和结尾间的空字符串\n",
    "#总结来就是\\b匹配单词边界\n",
    "#而\\B匹配非单词边界\n",
    "# \\< 匹配单词的开始  \\>匹配单词的结束\n",
    "import re\n",
    "m0 = re.search(r'ou\\b','you or yours')\n",
    "print(m0)\n",
    "m0 = re.search(r'ou\\b.','you or yours')\n",
    "print(m0)\n",
    "m1 = re.search(r'ou\\B','you or yours')\n",
    "print(m1)\n",
    "m1 = re.search(r'ou\\B.','you or yours')\n",
    "print(m1)\n",
    "print(re.search(r'\\<you\\>','you'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(10, 14), match='(任哥)'>\n",
      "(任哥)\n",
      "任哥\n",
      "('任哥',)\n"
     ]
    }
   ],
   "source": [
    "#正则表达式编译，可以通过编译，加速后面的匹配\n",
    "tkt = \"填空题：大家没有见过(任哥)，其实(任哥)只是个传说,要信(春哥)不挂科\" \n",
    "#\\(匹配括号\n",
    "#（）匹配分组\n",
    "#\\w匹配字母数字\n",
    "pattern = re.compile(r\"\\((\\w*)\\)\")\n",
    "m2 = re.search(pattern,tkt)\n",
    "print(m2)\n",
    "print(m2.group())\n",
    "print(m2.group(1))\n",
    "print(m2.groups())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "None\n",
      "<re.Match object; span=(0, 33), match='填空题：大家没有见过(任哥)，其实(任哥)只是个传说,要信(春哥)'>\n",
      "填空题：大家没有见过(任哥)，其实(任哥)只是个传说,要信(春哥)\n",
      "春哥\n",
      "('春哥',)\n"
     ]
    }
   ],
   "source": [
    "#如何验证字符串是否匹配  re.match\n",
    "#由于match一般是从头匹配的，还用上面的pattern将会什么也得不到\n",
    "import re\n",
    "tkt = \"填空题：大家没有见过(任哥)，其实(任哥)只是个传说,要信(春哥)不挂科\" \n",
    "pattern = re.compile(r\"\\((\\w*)\\)\")\n",
    "m3 = re.match(pattern,tkt)\n",
    "print(m3)\n",
    "pattern2 = re.compile(r\"^\\S*\\((\\w*)\\)\")\n",
    "#也可以通过pattern2直接调用match\n",
    "m3=pattern2.match(tkt)\n",
    "print(m3)\n",
    "print(m3.group())\n",
    "print(m3.group(1))\n",
    "print(m3.groups())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(10, 33), match='(任哥)，其实(任哥)只是个传说,要信(春哥)'>\n",
      "(任哥)，其实(任哥)只是个传说,要信(春哥)\n",
      "春哥\n",
      "('任哥', '任哥', '春哥')\n"
     ]
    }
   ],
   "source": [
    "#前面的group只有一个，如果有多个（）的话，就会有多个group\n",
    "pattern3 = re.compile(r\"\\((\\w*)\\)\\S*\\((\\w*)\\)\\S*\\((\\w*)\\)\")\n",
    "m4 = pattern3.search(tkt)\n",
    "print(m4)\n",
    "print(m4.group())\n",
    "print(m4.group(3))\n",
    "print(m4.groups())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(6, 14), match='-hahaha\\n'>\n",
      "-hahaha\n",
      "\n",
      "hahaha\n",
      "<re.Match object; span=(6, 41), match='-hahaha\\n100001-hehehe\\n100001-hahaha'>\n",
      "('hahaha',)\n",
      "hahaha\n"
     ]
    }
   ],
   "source": [
    "#在分组中，我们可以对分组进行命名，而不只是使用下表来访问\n",
    "#比如\n",
    "import re\n",
    "config = \"\"\"100000-hahaha\n",
    "100001-hehehe\n",
    "100001-hahaha\"\"\"\n",
    "m0 = re.search('-(?P<xm>\\w*)\\n',config)\n",
    "print(m0)\n",
    "print(m0.group())\n",
    "print(m0.group('xm'))\n",
    "#可以通过?P来匹配重复的字符串，如果没有重复则匹配不到,如果有重复，不会增加分组。\n",
    "m1 = re.search('-(?P<xm>.*)\\n.*(?P=xm)',config,re.S)\n",
    "print(m1)\n",
    "print(m1.groups())\n",
    "print(m1.group('xm'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(10, 20), match='100001-He\\n'>\n",
      "He\n",
      "<re.Match object; span=(0, 10), match='100000-ha\\n'>\n",
      "ha\n"
     ]
    }
   ],
   "source": [
    "#(?imx: re)\t在括号中使用i, m, 或 x 可选标志，这样就不需要传递最后的flag标志了\n",
    "config = \"\"\"100000-ha\n",
    "100001-He\n",
    "100001-ha\"\"\"\n",
    "m0 = re.search('.*-([Hae]*)\\n',config)\n",
    "print(m0)\n",
    "print(m0.group(1))\n",
    "m1 = re.search('(?i).*-([Hae]*)\\n',config)\n",
    "print(m1)\n",
    "print(m1.group(1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 107,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(?=:)\\w+ []\n",
      "(?!:)\\w+ ['stuid', '007', 'stuname', 'haha', 'tel', '13813886066']\n",
      "(?=s)\\w+ ['stuid', 'stuname']\n",
      "(?!s)\\w+ ['tuid', '007', 'tuname', 'haha', 'tel', '13813886066']\n",
      "\\w+(?=:) ['stuid', 'stuname', 'tel']\n",
      "\\w+(?!:) ['stui', '007', 'stunam', 'haha', 'te', '13813886066']\n",
      "\\w+(?=e) ['stunam', 't']\n",
      "\\w+(?!e) ['stuid', '007', 'stuname', 'haha', 'tel', '13813886066']\n"
     ]
    }
   ],
   "source": [
    "#(?=...)匹配到...的内容,如果...在前则包含，若在后，则不包含\n",
    "#...在前的情况,包含...\n",
    "#(?!…) 匹配不符合...的情况\n",
    "stuinfo = \"stuid:007,stuname:haha,tel:13813886066\"\n",
    "pattern = r'(?=:)\\w+'  #:并不属于\\w+所以如果包含:,那么永远不满足\\w+\n",
    "m0 = re.findall(pattern,stuinfo)\n",
    "print(pattern,m0)\n",
    "pattern = r'(?!:)\\w+'\n",
    "m0 = re.findall(pattern,stuinfo) #匹配除上面之外的\\w+\n",
    "print(pattern,m0)\n",
    "\n",
    "pattern = r'(?=s)\\w+'  #s属于\\w+,所以结果中也包括s\n",
    "m1 = re.findall(pattern,stuinfo)\n",
    "print(pattern,m1)\n",
    "pattern = r'(?!s)\\w+'  \n",
    "m1 = re.findall(pattern,stuinfo)\n",
    "print(pattern,m1)\n",
    "\n",
    "#...在后的情况,不包含...\n",
    "pattern = r'\\w+(?=:)'     #:虽然不属于\\w+,但：在右边并不会包含在结果中。\n",
    "m2 = re.findall(pattern,stuinfo)\n",
    "print(pattern,m2) \n",
    "pattern = r'\\w+(?!:)'     \n",
    "m2 = re.findall(pattern,stuinfo)\n",
    "print(pattern,m2) \n",
    "\n",
    "pattern = r'\\w+(?=e)'\n",
    "m3 = re.findall(pattern,stuinfo)\n",
    "print(pattern,m3)\n",
    "pattern = r'\\w+(?!e)'\n",
    "m3 = re.findall(pattern,stuinfo)\n",
    "print(pattern,m3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 108,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(?<=:)\\w+ ['007', 'haha', '13813886066']\n",
      "(?<!:)\\w+ ['stuid', '07', 'stuname', 'aha', 'tel', '3813886066']\n",
      "(?<=s)\\w+ ['tuid', 'tuname']\n",
      "(?<!s)\\w+ ['stuid', '007', 'stuname', 'haha', 'tel', '13813886066']\n",
      "\\w+(?<=:) []\n",
      "\\w+(?<!:) ['stuid', '007', 'stuname', 'haha', 'tel', '13813886066']\n",
      "\\w+(?<=e) ['stuname', 'te']\n",
      "\\w+(?<!e) ['stuid', '007', 'stunam', 'haha', 'tel', '13813886066']\n"
     ]
    }
   ],
   "source": [
    "#(?<=...) 匹配到...所表示字符串后的位置\n",
    "#...在前的情况,不包含...\n",
    "#(?<!...) 匹配不符合...\n",
    "stuinfo = \"stuid:007,stuname:haha,tel:13813886066\"\n",
    "pattern = r'(?<=:)\\w+' \t# 匹配到:后，满足\\w+的数据\n",
    "m0 = re.findall(pattern,stuinfo)\n",
    "print(pattern,m0)\n",
    "pattern = r'(?<!:)\\w+' \t# 匹配除上面之外的\\w+\n",
    "m0 = re.findall(pattern,stuinfo)\n",
    "print(pattern,m0)\n",
    "\n",
    "pattern = r'(?<=s)\\w+'\n",
    "m1 = re.findall(pattern,stuinfo)\n",
    "print(pattern,m1)\n",
    "pattern = r'(?<!s)\\w+'\n",
    "m1 = re.findall(pattern,stuinfo)\n",
    "print(pattern,m1)\n",
    "\n",
    "#...在后的情况,包含...\n",
    "pattern = r'\\w+(?<=:)'     #:并不属于\\w+所以如果包含:,那么永远不满足\\w+\n",
    "m2 = re.findall(pattern,stuinfo)\n",
    "print(pattern,m2) \n",
    "pattern = r'\\w+(?<!:)'     #:并不属于\\w+所以如果包含:,那么永远不满足\\w+\n",
    "m2 = re.findall(pattern,stuinfo)\n",
    "print(pattern,m2) \n",
    "\n",
    "pattern = r'\\w+(?<=e)'\n",
    "m3 = re.findall(pattern,stuinfo)\n",
    "print(pattern,m3)\n",
    "pattern = r'\\w+(?<!e)'\n",
    "m3 = re.findall(pattern,stuinfo)\n",
    "print(pattern,m3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 104,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "m0 ['stuid', '007', 'stuname', 'haha', 'tel', '13813886066']\n",
      "m1 ['tuid', '007', 'tuname', 'haha', 'tel', '13813886066']\n"
     ]
    }
   ],
   "source": [
    "\n",
    "stuinfo = \"stuid:007,stuname:haha,tel:13813886066\"\n",
    "pattern = r'(?!:)\\w+'  #:并不属于\\w+所以如果包含:,那么永远不满足\\w+\n",
    "m0 = re.findall(pattern,stuinfo)\n",
    "print(\"m0\",m0)\n",
    "pattern = r'(?!s)\\w+'  #s属于\\w+,所以结果中也包括s\n",
    "m1 = re.findall(pattern,stuinfo)\n",
    "print(\"m1\",m1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['任哥', '任哥', '春哥']\n",
      "<class 'list'>\n"
     ]
    }
   ],
   "source": [
    "\n",
    "m5 = pattern.findall(tkt)\n",
    "print(m5)\n",
    "print(type(m5))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "填空题：大家没有见过哈哈，其实哈哈只是个传说,要信哈哈不挂科\n"
     ]
    }
   ],
   "source": [
    "#我们还可以替换掉文本中的文字 re.sub(pattern, repl, string, count=0, flags=0)\n",
    "#pattern : 正则中的模式字符串。\n",
    "#repl : 替换的字符串，也可为一个函数。\n",
    "#string : 要被查找替换的原始字符串。\n",
    "#count : 模式匹配后替换的最大次数，默认 0 表示替换所有的匹配。\n",
    "r = re.sub(pattern,'哈哈',tkt,0)\n",
    "print(r)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(0, 9), match='hahahahaα'>\n",
      "<re.Match object; span=(0, 14), match='hahahaha哈哈哈哈一壹'>\n",
      "<re.Match object; span=(0, 0), match=''>\n",
      "<re.Match object; span=(3, 5), match='呵呵'>\n",
      "None\n",
      "<re.Match object; span=(0, 2), match='哈哈'>\n",
      "None\n",
      "<re.Match object; span=(0, 5), match='哈哈\\n呵呵'>\n",
      "<re.Match object; span=(0, 2), match='哈哈'>\n",
      "<re.Match object; span=(0, 4), match='Good'>\n",
      "0\n",
      "4\n",
      "<re.Match object; span=(6, 10), match='-任哥-'>\n",
      "-任哥-\n",
      "任哥\n",
      "('任哥',)\n"
     ]
    }
   ],
   "source": [
    "#正则表达式的标记flags\n",
    "#re.A或re.ASCII\t是\\b\\B\\S\\w\\W都假定字符串为ASCII码，如果不指定\n",
    "#re.I或re.IGNORECASE\t使匹配对大小写不敏感\n",
    "#re.L\t做本地化识别（locale-aware）匹配，使\\w, \\W, \\b, \\B和大小写符合本地化规范,仅支持8-bit本地化识别\n",
    "#re.M\t多行匹配，影响 ^ 和 $\n",
    "#re.S\t使 . 匹配包括换行在内的所有字符\n",
    "#re.U\t根据Unicode字符集解析字符。这个标志影响 \\w, \\W, \\b, \\B.\n",
    "#re.X\t该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。\n",
    "\n",
    "#\\w匹配字母数字及下划线\n",
    "m0 = re.match(\"\\w*\",\"hahahahaα\")\n",
    "print(m0)\n",
    "#如果不指定re.A标记，则可以识别中文（unicode字符）\n",
    "m1 = re.match(\"\\w*\",\"hahahaha哈哈哈哈一壹\")\n",
    "print(m1)\n",
    "#此处用了re.A将不会匹配中文\n",
    "m2 = re.match(\"\\w*\",\"哈哈哈哈哈\",re.A)\n",
    "print(m2)\n",
    "\n",
    "#多行匹配,加上re.M每行都可以进行单独匹配，不加的话就是整个字符串进行匹配\n",
    "mline = '''哈哈\n",
    "呵呵'''\n",
    "m0 = re.search('^呵呵',mline,re.M)\n",
    "print(m0)\n",
    "m1 = re.search('^呵呵',mline)\n",
    "print(m1)\n",
    "m0 = re.search('哈哈$',mline,re.M)\n",
    "print(m0)\n",
    "m1 = re.search('哈哈$',mline)\n",
    "print(m1)\n",
    "\n",
    "#.也可以匹配所有字符\n",
    "m0 = re.search('.*',mline,re.S)\n",
    "print(m0)\n",
    "m1 = re.search('.*',mline)\n",
    "print(m1)\n",
    "\n",
    "#大小写不敏感\n",
    "m0 = re.search(\"Good\",\"Good good study Day day up\",re.I)\n",
    "print(m0)\n",
    "print(m0.start())\n",
    "print(m0.end())\n",
    "\n",
    "\n",
    "m1 = re.search(r\"-(\\w*)-\",\"大家没有见过-任哥-，其实-任哥-只是个传说，要信-春哥-不挂科\",re.U)\n",
    "print(m1)\n",
    "print(m1.group())\n",
    "print(m1.group(1))\n",
    "#设置了组，所以groups里面有了东西\n",
    "print(m1.groups())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#输入一个字符串空格隔开，获取其中所有的标识符\n",
    "#\\W匹配非字母下划线\n",
    "str = input(\"请输入一串字符串(以空格隔开):\")\n",
    "pat = r\"\\b[a-z]\\w*\"\n",
    "ans= re.findall(pat, str)\n",
    "print(\"合法的字符串有：\", ans)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#任务7-2  提取出下列文字中的英文单词\n",
    "#\"自由软件的出现成就了SQL Server数据库管理系统、Python程序设计语言、TCP/IP协议、Apache服务器软件、Linux操作系统等一大批自由软件精品。\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#任务7-3 提取出下列选择题的 题干 A,B,C,D和答案\n",
    "#十进制算式7×64+4×8+5的运算结果用二进制表示为_______。 B\n",
    "#A.110100101    B.111100101\n",
    "#C.110100101    D.111101101\n",
    "#总线最重要的性能指标是它的带宽。若总线的数据线宽度为64位，总线的工作频率为133MHz，每个总线周期传输两次数据，则其带宽为________。B\n",
    "#A.17GB/s\t\tB.2128MB/s\t\tC.8512MB/s\t\tD.1064MB/s\n",
    "#在PC机中RAM内存储器的编址单位是________。C\n",
    "#A.1个簇   B.1个二进制位    C.1个字节\tD.1个扇区"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### itertools的使用\n",
    "python内置的itertools提供了一些很好用的功能。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['甲子', '甲丑', '甲寅', '甲卯', '甲辰', '甲巳', '甲午', '甲未', '甲申', '甲酉', '甲戌', '甲亥', '乙子', '乙丑', '乙寅', '乙卯', '乙辰', '乙巳', '乙午', '乙未', '乙申', '乙酉', '乙戌', '乙亥', '丙子', '丙丑', '丙寅', '丙卯', '丙辰', '丙巳', '丙午', '丙未', '丙申', '丙酉', '丙戌', '丙亥', '丁子', '丁丑', '丁寅', '丁卯', '丁辰', '丁巳', '丁午', '丁未', '丁申', '丁酉', '丁戌', '丁亥', '戊子', '戊丑', '戊寅', '戊卯', '戊辰', '戊巳', '戊午', '戊未', '戊申', '戊酉', '戊戌', '戊亥', '己子', '己丑', '己寅', '己卯', '己辰', '己巳', '己午', '己未', '己申', '己酉', '己戌', '己亥', '庚子', '庚丑', '庚寅', '庚卯', '庚辰', '庚巳', '庚午', '庚未', '庚申', '庚酉', '庚戌', '庚亥', '辛子', '辛丑', '辛寅', '辛卯', '辛辰', '辛巳', '辛午', '辛未', '辛申', '辛酉', '辛戌', '辛亥', '壬子', '壬丑', '壬寅', '壬卯', '壬辰', '壬巳', '壬午', '壬未', '壬申', '壬酉', '壬戌', '壬亥', '癸子', '癸丑', '癸寅', '癸卯', '癸辰', '癸巳', '癸午', '癸未', '癸申', '癸酉', '癸戌', '癸亥']\n",
      "120\n"
     ]
    }
   ],
   "source": [
    "import itertools\n",
    "#今年是庚子年，中国特有的天干地支表示年份的方法\n",
    "天干='甲乙丙丁戊己庚辛壬癸'\n",
    "地支='子丑寅卯辰巳午未申酉戌亥'\n",
    "#中国的循环是这样的\n",
    "#甲乙丙丁戊己庚辛壬癸甲乙丙丁戊己庚辛壬癸甲乙丙丁戊己庚辛壬癸甲乙丙丁戊己庚辛壬癸甲乙丙丁戊己庚辛壬癸甲乙丙丁戊己庚辛壬癸\n",
    "#子丑寅卯辰巳午未申酉戌亥子丑寅卯辰巳午未申酉戌亥子丑寅卯辰巳午未申酉戌亥子丑寅卯辰巳午未申酉戌亥子丑寅卯辰巳午未申酉戌亥\n",
    "#itertools.product方法是一一配对，这个和中国的年代表示是不一样的，中国的是60年一个循环，大家可以自己实现以下。\n",
    "it = itertools.product(天干,地支)\n",
    "all = [''.join(item) for item in it]\n",
    "print(all)\n",
    "print(len(all))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "repeat(10)"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#无穷遍历\n",
    "it1 = itertools.count(1)\n",
    "it2 = itertools.cycle('ABC')\n",
    "it3 = itertools.repeat(10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### JSON的编解码\n",
    "在WEB时代，json是非常广泛的数据传输方式，基于文本，易于阅读。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\"01\": \"\\u7eff\\u7801\", \"02\": \"\\u9ec4\\u7801\", \"03\": \"\\u7ea2\\u7801\", \"04\": \"\\u84dd\\u9a6c\"} <class 'str'>\n",
      "{'01': '绿码', '02': '黄码', '03': '红码', '04': '蓝马'} <class 'dict'>\n"
     ]
    }
   ],
   "source": [
    "#字典和json字符串的转换\n",
    "import json\n",
    "kp = {\"01\":\"绿码\",\"02\":\"黄码\",\"03\":\"红码\",\"04\":\"蓝马\"}\n",
    "kpjson = json.dumps(kp)\n",
    "print(kpjson,type(kpjson))\n",
    "kpnew = json.loads(kpjson)\n",
    "print(kpnew,type(kpnew))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'dict'>\n",
      "{'01': '绿码', '02': '黄码', '03': '红码', '04': '蓝马'}\n"
     ]
    }
   ],
   "source": [
    "#读写文件中的json\n",
    "with open('kpjson.json','w') as fkpjson:\n",
    "    json.dump(kp,fkpjson)\n",
    "    \n",
    "with open('kpjson.json','r') as fkpnew:\n",
    "    result = json.load(fkpnew)\n",
    "    print(type(result))\n",
    "    print(result)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### os模块\n",
    "os模块提供了Python和操作系统进行交互的接口"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "E:\\courses\\python\\pythonbook\\pythonstudy\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "#当前工作目录\n",
    "dir = os.getcwd()\n",
    "print(dir)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "('E:\\\\courses\\\\python\\\\pythonbook\\\\pythonstudy', ['%HOMEDRIVE%%HOMEPATH%', '.git', '.ipynb_checkpoints', 'flaskproject', 'mysite', 'phealth', '__pycache__'], ['ASCII码表.ipynb', 'chars.txt', 'excel.xlsx', 'haha.txt', 'health.py', 'hehe.txt', 'kpjson.json', 'number.txt', 'pythoninfo-cn.txt', 'pythoninfo.txt', 'pythoninfor-cn.txt', 'pythoninfor.txt', 'README.md', 'stuscore.txt', 'task0 安装python.ipynb', 'task1 安装VSCode或者Pycharm.ipynb', 'task10 课程结束.ipynb', 'task2 Python基础.ipynb', 'task3 数据结构.ipynb', 'task4 函数.ipynb', 'task5 函数式编程.ipynb', 'task6 面向对象编程.ipynb', 'task7 脚本、模块、包、库.ipynb', 'task8 并发和并行.ipynb', 'task9 第三方包.ipynb', 'testwordcloud.png', 'testwordcloudnosw.png', 'untitled.txt', '安徒生童话.txt'])\n",
      "E:\\courses\\python\\pythonbook\\pythonstudy\n",
      "['%HOMEDRIVE%%HOMEPATH%', '.git', '.ipynb_checkpoints', 'flaskproject', 'mysite', 'phealth', '__pycache__']\n",
      "['ASCII码表.ipynb', 'chars.txt', 'excel.xlsx', 'haha.txt', 'health.py', 'hehe.txt', 'kpjson.json', 'number.txt', 'pythoninfo-cn.txt', 'pythoninfo.txt', 'pythoninfor-cn.txt', 'pythoninfor.txt', 'README.md', 'stuscore.txt', 'task0 安装python.ipynb', 'task1 安装VSCode或者Pycharm.ipynb', 'task10 课程结束.ipynb', 'task2 Python基础.ipynb', 'task3 数据结构.ipynb', 'task4 函数.ipynb', 'task5 函数式编程.ipynb', 'task6 面向对象编程.ipynb', 'task7 脚本、模块、包、库.ipynb', 'task8 并发和并行.ipynb', 'task9 第三方包.ipynb', 'testwordcloud.png', 'testwordcloudnosw.png', 'untitled.txt', '安徒生童话.txt']\n",
      "('hahahah.hahah', '.txt')\n",
      "('ASCII码表', '.ipynb')\n",
      "E:\\courses\\python\\pythonbook\\pythonstudy\\ASCII码表.ipynb\n"
     ]
    }
   ],
   "source": [
    "#获取目录树\n",
    "#按深度优先获得目录结果\n",
    "files = os.walk(dir)\n",
    "for f in files:\n",
    "    #每个文件多是元组形式，参数0是目录，参数1是子目录，参数2是目录下的所有文件\n",
    "    print(f)\n",
    "    print(f[0])\n",
    "    print(f[1])\n",
    "    print(f[2])\n",
    "    # os.path.splitext 分离扩展名\n",
    "    print(os.path.splitext('hahahah.hahah.txt'))\n",
    "    print(os.path.splitext(f[2][0]))\n",
    "    # os.path.join 合并文件路径\n",
    "    print(os.path.join(f[0],f[2][0]))\n",
    "    break;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 随机数random"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "返回  [0,1)之间的数字: 0.405305104554358\n",
      "返回[1,n)之间的数字: 5.424459210694626\n",
      "返回[1,10]之间的整数 1\n",
      "返回[0,100]之间的偶数 14\n",
      "选择其中一张牌: 4\n",
      "乱序: ['7', '5', '1', 'K', '2', 'J', '3', '9', '8', '6', '4', 'Q', 'A', '10']\n",
      "抓到: ['6', '5', '7', 'A']\n",
      "随机3位二进制数字110\n",
      "随机8位二进制数字01000011\n"
     ]
    }
   ],
   "source": [
    "import random\n",
    "print(\"返回  [0,1)之间的数字:\",random.random())\n",
    "n=8\n",
    "print(\"返回[1,n)之间的数字:\", random.uniform(1,n))\n",
    "print(\"返回[1,10]之间的整数\", random.randint(1,10))\n",
    "print(\"返回[0,100]之间的偶数\", random.randrange(0,101,2))\n",
    "\n",
    "pai = ['A','1','2','3','4','5','6','7','8','9','10','J','Q','K']\n",
    "print(\"选择其中一张牌:\", random.choice(pai))\n",
    "random.shuffle(pai)\n",
    "print(\"乱序:\", pai)\n",
    "zhua = random.sample(pai,4)\n",
    "#大家试试24点\n",
    "print(\"抓到:\",zhua)\n",
    "\n",
    "#随机一个n位二进制以内的数字,不够n位，前面补0\n",
    "print(\"随机3位二进制数字{:0>3b}\".format(random.getrandbits(3)))\n",
    "print(\"随机8位二进制数字{:0>8b}\".format(random.getrandbits(8)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "49 97 53 5 33\n",
      "49 97 53 5 33\n",
      "49 97\n",
      "53 5 33 65\n",
      "53 5 33 65\n"
     ]
    }
   ],
   "source": [
    "#random随机的原理是依赖一个种子数，然后通过算法产生数据序列。如果一样的种子，产生的序列就是一样的。\n",
    "#random.seed(a=None,version=2)\n",
    "#如果种子a是None，那么就使用系统时间作为参数\n",
    "#同一个种子下产生的随机序列是一样的\n",
    "import random\n",
    "random.seed(0)\n",
    "print(random.randint(0,100),random.randint(0,100),random.randint(0,100),random.randint(0,100),random.randint(0,100))\n",
    "random.seed(0)\n",
    "print(random.randint(0,100),random.randint(0,100),random.randint(0,100),random.randint(0,100),random.randint(0,100))\n",
    "#可以通过random.getstate()保存随机生成器的当前状态，并通过random.setstate(state)设置随机生成器当前状态，比如\n",
    "random.seed(0)\n",
    "print(random.randint(0,100),random.randint(0,100))\n",
    "state = random.getstate()\n",
    "print(random.randint(0,100),random.randint(0,100),random.randint(0,100),random.randint(0,100))\n",
    "random.setstate(state)\n",
    "print(random.randint(0,100),random.randint(0,100),random.randint(0,100),random.randint(0,100))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 路径操作 pathlib"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "路径存在吗？ True\n",
      "是目录吗？ True\n",
      "工作目录: E:\\courses\\python\\pythonbook\\pythonstudy\n",
      "工作目录下所有python文件: E:\\courses\\python\\pythonbook\\pythonstudy\\health.py,E:\\courses\\python\\pythonbook\\pythonstudy\\phealth\\health.py,E:\\courses\\python\\pythonbook\\pythonstudy\\phealth\\__init__.py\n"
     ]
    }
   ],
   "source": [
    "import pathlib\n",
    "path = pathlib.Path('.')\n",
    "print(\"路径存在吗？\",path.exists())\n",
    "print(\"是目录吗？\", path.is_dir())\n",
    "workdir = pathlib.Path.cwd()\n",
    "print(\"工作目录:\",workdir)\n",
    "#查找文件*表示任意0-n个字符，？表示1个字符，[]字符范围\n",
    "#**是python3.5开始推出的，表示所有目录\n",
    "print(\"工作目录下所有python文件:\",','.join(str(f) for f in workdir.glob('**/*.py')))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 执行程序"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "请输入指令：mstsc /v:renge.pub:60001\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "0"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#subprocess可以执行各种本机程序\n",
    "import subprocess\n",
    "#subprocess.call([\"mstsc\"])\n",
    "#可以带上参数\n",
    "#subprocess.call([\"mstsc\", \"/v:renge.pub:60001\"])\n",
    "#如果带参数，可以使用shlex\n",
    "import shlex\n",
    "command = input(\"请输入指令：\")\n",
    "c = shlex.split(command)\n",
    "subprocess.call(c)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 美化输出"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'01': '绿码', '02': '黄码', '03': '红码', '04': '蓝马'}\n",
      "{'01': '绿码',\n",
      " '02': '黄码',\n",
      " '03': '红码',\n",
      " '04': '蓝马'}\n"
     ]
    }
   ],
   "source": [
    "#pretty print\n",
    "import pprint\n",
    "import pathlib\n",
    "print(kp)\n",
    "pprint.pprint(k   p,width=10)   "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 计时器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2.3573043999999754"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import timeit\n",
    "timeit.timeit('\"-\".join(str(n) for n in range(100))', number=100000)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 绘图"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "#使用turtle库绘制红色五角星\n",
    "import turtle\n",
    "turtle.color('red', 'red')\n",
    "turtle.begin_fill()\n",
    "while True:\n",
    "    turtle.forward(300)\n",
    "    turtle.left(144)\n",
    "    if abs(turtle.pos()) < 1:\n",
    "        break\n",
    "turtle.end_fill()\n",
    "turtle.done()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "import turtle\n",
    "turtle.color('red', 'red')\n",
    "turtle.begin_fill()\n",
    "while True:\n",
    "    turtle.forward(300)\n",
    "    turtle.left(150)\n",
    "    if abs(turtle.pos()) < 1:\n",
    "        break\n",
    "turtle.end_fill()\n",
    "turtle.done()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [],
   "source": [
    "import turtle\n",
    "turtle.color('red', 'red')\n",
    "turtle.begin_fill()\n",
    "while True:\n",
    "    turtle.forward(200)\n",
    "    turtle.left(72)\n",
    "    if abs(turtle.pos()) < 1:\n",
    "        break\n",
    "turtle.end_fill()\n",
    "turtle.done()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#任务7-4 创建函数，绘制n变形,参数为n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#任务7-5 创建函数,绘制n角形，参数为n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
